package com.colorfruit.admin.business.service.impl;

import com.colorfruit.admin.business.dao.*;
import com.colorfruit.admin.business.service.PayBusinessOrderService;
import com.colorfruit.admin.outer.weixin.WxUtil;
import com.colorfruit.admin.pojo.constant.CommonConstant;
import com.colorfruit.admin.pojo.entity.*;
import com.colorfruit.admin.pojo.enums.*;
import com.colorfruit.admin.pojo.outer.WxPayResponse;
import com.colorfruit.admin.pojo.vo.payorder.*;
import com.colorfruit.framework.common.idgenerate.BizNumberType;
import com.colorfruit.framework.common.idgenerate.DateTimeIdGenerator;
import com.colorfruit.framework.common.util.BusinessUtil;
import com.colorfruit.framework.common.util.CommonUtil;
import com.colorfruit.framework.common.util.DataConvertUtil;
import com.colorfruit.framework.common.util.DataValidateUtil;
import com.colorfruit.framework.model.admin.CommonDate;
import com.colorfruit.framework.model.pojo.BaseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@Transactional
public class PayBusinessOrderServiceImpl implements PayBusinessOrderService {

    @Autowired
    PayBusinessOrderMapper payBusinessOrderMapper;  //支付业务订单

    @Autowired
    PayBusinessOrderItemMapper payBusinessOrderItemMapper; //支付业务订单明细

    @Autowired
    PreShelfOrderMapper preShelfOrderMapper; //预上架订单

    @Autowired
    ConfigCommonMapper configCommonMapper; //配置文件

    @Autowired
    PayWxOrderMapper payWxOrderMapper; //微信支付订单

    @Autowired
    PayWxOrderItemMapper payWxOrderItemMapper; //微信支付订单明细

    @Autowired
    FoundationSysUserMapper sysUserMapper; //用户

    @Autowired
    PayUserWalletFlowMapper payUserWalletFlowMapper;//钱包流水

    @Autowired
    FoundationUserReceiveAddressMapper userReceiveAddressMapper; //用户收货地址

    @Autowired
    FoundationPickGoodsAddressMapper pickGoodsAddressMapper; //拣货点地址

    @Autowired
    GlobalProcessionControlMapper globalProcessionControlMapper;

    @Autowired
    ShoppingCartMapper shoppingCartMapper;

    //APPid
    @Value("${app_id}")
    private String app_id;

    //商户号
    @Value("${mch_id}")
    private String mch_id;

    //api秘钥key
    @Value("${api_key}")
    private String api_key;

    @Value("${call_back_url_domain}")
    private String call_back_url_domain;

    @Value("${call_back_mapping}")
    private String call_back_mapping;

    @Override
    public BaseResult generatePayOrder(String userId, List<GeneratePayVo> generatePayVoList)  {
        log.info("[service] [IN] generatePayOrder param : userId = {}, generatePayVoList.size = {}", userId, generatePayVoList.size());
        ConfigCommon distributionConfig = configCommonMapper.getConfigInfoByCode(CommonConstant.DISTRIBUTION_COST);
        GlobalProcessionControl globalProcessionControl = globalProcessionControlMapper.getRecentProcession();
        //1. 变更支付业务订单信息
        PayBusinessOrder payBusinessOrder = new PayBusinessOrder();
        PayBusinessOrder recentOrder = payBusinessOrderMapper.getRecentOrder(userId);
        String businessNo = DateTimeIdGenerator.nextNo(BizNumberType.PB);

        BigDecimal totalMaxSaleAmount = new BigDecimal(0);
        BigDecimal totalMinSaleAmount = new BigDecimal(0);
        int totalNum = 0;
        for (GeneratePayVo generatePayVo : generatePayVoList) {
            //变更购物车数据状态未未支付
            shoppingCartMapper.updateProductStatus(userId, generatePayVo.getPreShelfOrderId(), ShoppingCartEnum.NOT_PAY.getCode());

            PreShelfOrder preShelfOrder = preShelfOrderMapper.selectByPrimaryKey(generatePayVo.getPreShelfOrderId());
            PayBusinessOrderItem payBusinessOrderItem = new PayBusinessOrderItem();
            payBusinessOrderItem.setBusinessOrderNo(businessNo);
            payBusinessOrderItem.setRecordStatus(PayBusinessOrderEnum.NOT_CONFIRM.getCode());
            payBusinessOrderItem.setUserId(userId);
            payBusinessOrderItem.setProductId(preShelfOrder.getProductId());
            payBusinessOrderItem.setPreShelfOrderId(generatePayVo.getPreShelfOrderId());
            payBusinessOrderItem.setItemSaleMaxPrice(preShelfOrder.getSaleMaxPrice());
            payBusinessOrderItem.setItemSaleMinPrice(preShelfOrder.getSaleMinPrice());
            payBusinessOrderItem.setItemProductNum(generatePayVo.getProductNum());
            payBusinessOrderItemMapper.insert(payBusinessOrderItem);

            BigDecimal productNum = new BigDecimal(payBusinessOrderItem.getItemProductNum());
            totalMaxSaleAmount = totalMaxSaleAmount.add(preShelfOrder.getSaleMaxPrice().multiply(productNum));
            totalMinSaleAmount = totalMinSaleAmount.add(preShelfOrder.getSaleMinPrice().multiply(productNum));
            totalNum = totalNum + generatePayVo.getProductNum();

        }
        if (recentOrder != null) {
            payBusinessOrder.setAddressType(recentOrder.getAddressType());
            payBusinessOrder.setReceiveAddressId(recentOrder.getReceiveAddressId());
            if (recentOrder.getAddressType() == AddressTypeEnum.PERSONAL_ADDRESS.getCode()){
                payBusinessOrder.setDistributeFee(new BigDecimal(distributionConfig.getConfigValue()));
            }
        }
        payBusinessOrder.setGlobalControlId(globalProcessionControl.getId());
        payBusinessOrder.setTotalSaleMaxAmount(totalMaxSaleAmount);
        payBusinessOrder.setTotalSaleMinAmount(totalMinSaleAmount);
        payBusinessOrder.setTotalProductNum(totalNum);
        payBusinessOrder.setTotalFee(payBusinessOrder.getTotalSaleMaxAmount().add(payBusinessOrder.getDistributeFee()));
        payBusinessOrder.setDistributeStatus(DistributeStatusEnum.WAIT_DISTRIBUTE.getCode());
        payBusinessOrder.setUserId(userId);
        payBusinessOrder.setBusinessOrderNo(businessNo);
        payBusinessOrder.setRecordStatus(PayBusinessOrderEnum.NOT_CONFIRM.getCode());
        payBusinessOrder.setCreateTime(new Date());
        payBusinessOrder.setUpdateTime(new Date());
        payBusinessOrderMapper.insert(payBusinessOrder);
        log.info("[service] [OUT] generatePayOrder success ");
        return new BaseResult(payBusinessOrder.getBusinessOrderNo());
    }

    @Override
    public BaseResult getPayOrder(String userId, String businessNo) {
        log.info("[service] [IN] getPayOrder param : userId = {}, businessNo = {}", userId, businessNo);

        PayBusinessVo payBusinessVo = new PayBusinessVo();
        PayBusinessOrder recentOrder = payBusinessOrderMapper.getRecentOrder(userId);
        PayBusinessOrder payBusinessOrder = payBusinessOrderMapper.getByBusinessNo(businessNo);
        if (!DataValidateUtil.verifyString(payBusinessOrder.getPhone()) || DataValidateUtil.verifyString(payBusinessOrder.getUserName())){
            FoundationSysUser foundationSysUser = sysUserMapper.selectByPrimaryKey(userId);
            payBusinessOrder.setUserName(foundationSysUser.getUserName());
            payBusinessOrder.setPhone(foundationSysUser.getContactPhone());
        }
        payBusinessVo.setPayBusinessOrder(payBusinessOrder);
        List<PayOrderItemVo> payBusinessOrderItems = payBusinessOrderItemMapper.selectOrderItemList(businessNo);
        payBusinessVo.setPayOrderItemVoList(payBusinessOrderItems);
        if (recentOrder != null){
            Byte addressType = recentOrder.getAddressType();
            payBusinessVo.setAddressType(addressType);
            if (addressType != null && addressType == AddressTypeEnum.PERSONAL_ADDRESS.getCode().byteValue()){
                FoundationUserReceiveAddress foundationUserReceiveAddress = userReceiveAddressMapper.selectByPrimaryKey(recentOrder.getReceiveAddressId());
                payBusinessVo.setFoundationUserReceiveAddress(foundationUserReceiveAddress);
            }else {
                FoundationPickGoodsAddress foundationPickGoodsAddress = pickGoodsAddressMapper.selectByPrimaryKey(recentOrder.getReceiveAddressId());
                payBusinessVo.setFoundationPickGoodsAddress(foundationPickGoodsAddress);
            }
        }
        log.info("[service] [OUT] getPayOrder success ");
        return new BaseResult(payBusinessVo);
    }

    @Override
    public BaseResult editPayOrder(String userId,
                                   String ip,
                                   PayBusinessOrderVo payBusinessOrderVo,
                                   List<PayBusinessOrderItemVo> payBusinessOrderItemVoList) throws Exception {
        log.info("[service] [IN] editPayOrder param : payBusinessOrderVo = {}", payBusinessOrderVo.toString());
        // 1. 编辑支付业务订单
        BaseResult baseResult ;
        StringBuffer businessIds = new StringBuffer();
        int i = 0;
        for (PayBusinessOrderItemVo payBusinessOrderItemVo : payBusinessOrderItemVoList) {
            // 1.1 更新业务订单明细数据
            PayBusinessOrderItem payBusinessOrderItem = new PayBusinessOrderItem();
            payBusinessOrderItem.setId(payBusinessOrderItemVo.getId());
            payBusinessOrderItem.setRecordStatus(PayBusinessOrderEnum.CONFIRMED.getCode());
            payBusinessOrderItemMapper.updateByPrimaryKeySelective(payBusinessOrderItem);
            if (i < payBusinessOrderItemVoList.size() - 1) {
                businessIds.append(payBusinessOrderItemVo.getId()).append(",");
            } else {
                businessIds.append(payBusinessOrderItemVo.getId());
            }
           i ++ ;
        }
        //1.2 更新业务订单数据
        PayBusinessOrder payBusinessOrderDb = payBusinessOrderMapper.selectByPrimaryKey(payBusinessOrderVo.getId());
        payBusinessOrderDb.setRecordStatus(PayBusinessOrderEnum.CONFIRMED.getCode());
        payBusinessOrderDb.setAddressType(payBusinessOrderVo.getAddressType());
        payBusinessOrderDb.setReceiveAddressId(payBusinessOrderVo.getReceiveAddressId());
        if (AddressTypeEnum.PERSONAL_ADDRESS.getCode().byteValue() == payBusinessOrderVo.getAddressType()) {
            FoundationUserReceiveAddress foundationUserReceiveAddress = userReceiveAddressMapper.selectByPrimaryKey(payBusinessOrderVo.getReceiveAddressId());
            log.info("个人地址");
            ConfigCommon configInfoByCode = configCommonMapper.getConfigInfoByCode(CommonConstant.DISTRIBUTION_COST);
            payBusinessOrderDb.setDistributeFee(new BigDecimal(configInfoByCode.getConfigValue()));
            payBusinessOrderDb.setDistributeAddressId(foundationUserReceiveAddress.getPickerAddressId());
            payBusinessOrderDb.setUserName(foundationUserReceiveAddress.getUserName());
            payBusinessOrderDb.setPhone(foundationUserReceiveAddress.getPhone());
        }else {
            log.info("拣货点地址");
            if (!DataValidateUtil.verifyString(payBusinessOrderVo.getPhone(), payBusinessOrderVo.getUserName())){
                return new BaseResult(ErrorCodeEnum.DATA_ERROR.getCode(),"拣货点用户名或地址为空,请重新核对");
            }
            payBusinessOrderDb.setPhone(payBusinessOrderVo.getPhone());
            payBusinessOrderDb.setUserName(payBusinessOrderVo.getUserName());
            payBusinessOrderDb.setDistributeAddressId(payBusinessOrderVo.getReceiveAddressId());
            payBusinessOrderDb.setDistributeFee(new BigDecimal(0));
            sysUserMapper.updateUserInfo(userId,
                    payBusinessOrderVo.getPhone(),
                    payBusinessOrderVo.getUserName()
                   );
        }
        payBusinessOrderDb.setTotalFee(payBusinessOrderDb.getTotalSaleMaxAmount().add(payBusinessOrderDb.getDistributeFee()));
        payBusinessOrderMapper.updateByPrimaryKeySelective(payBusinessOrderDb);

        //2. 生成支付订单
        // 2.1 生成微信支付订单信息
        String wpNo = DateTimeIdGenerator.nextNo(BizNumberType.WXP);

        FoundationSysUser foundationSysUser = sysUserMapper.selectByPrimaryKey(userId);
        PayWxOrder payWxOrder = new PayWxOrder();
        payWxOrder.setUserId(userId);
        payWxOrder.setAppid(app_id);
        payWxOrder.setMchId(mch_id);
        payWxOrder.setSpbillCreateIp(ip);
        payWxOrder.setRecordStatus(PayWxOrderStatusEnum.WAIT_PAY.getCode());
        payWxOrder.setPayOrderNo(wpNo);
        payWxOrder.setPreOnShelfIds(businessIds.toString());
        payWxOrder.setTotalFee(payBusinessOrderDb.getTotalFee());
        payWxOrder.setMonthAccountCheckingStatus(MonthCheckEnum.NOT_CHECK.getCode());
        payWxOrder.setBusinessOrderNo(payBusinessOrderDb.getBusinessOrderNo());
        if (foundationSysUser.getWalletBalance() != null
                && foundationSysUser.getWalletBalance().compareTo(new BigDecimal(0)) > 0){
            if (foundationSysUser.getWalletBalance().compareTo(payBusinessOrderDb.getTotalFee()) <= 0){
                payWxOrder.setWalletFee(DataConvertUtil.bigDecimal2notNull(foundationSysUser.getWalletBalance()));
                payWxOrder.setWaitPayFee(DataConvertUtil.bigDecimal2notNull(payWxOrder.getTotalFee().subtract(foundationSysUser.getWalletBalance())));
            }else {
                payWxOrder.setWalletFee(payWxOrder.getTotalFee());
                payWxOrder.setWaitPayFee(new BigDecimal(0));
            }
        }else {
            payWxOrder.setWalletFee(new BigDecimal(0));
            payWxOrder.setWaitPayFee(payWxOrder.getTotalFee());
        }
        payWxOrder.setActualPayFee(new BigDecimal("0"));
        payWxOrder.setCreateTime(new Date());
        payWxOrder.setUpdateTime(new Date());
        payWxOrderMapper.insert(payWxOrder);
        //2.2 生成微信支付订单明细
        for (PayBusinessOrderItemVo payBusinessOrderItemVo : payBusinessOrderItemVoList) {
            PayBusinessOrderItem payBusinessOrderItem = payBusinessOrderItemMapper.selectByPrimaryKey(payBusinessOrderItemVo.getId());
            // 更新支付订单明细数据
            PayWxOrderItem payWxOrderItem = new PayWxOrderItem();
            payWxOrderItem.setPayOrderNo(wpNo);
            payWxOrderItem.setBusinessOrderNo(payBusinessOrderDb.getBusinessOrderNo());
            payWxOrderItem.setPayWxOrderId(payWxOrder.getId());
            payWxOrderItem.setPreOnShelfId(payBusinessOrderItemVo.getPreShelfOrderId() + "");
            BigDecimal itemNum = new BigDecimal(payBusinessOrderItem.getItemProductNum());
            payWxOrderItem.setItemTotalFee(payBusinessOrderItem.getItemSaleMaxPrice().multiply(itemNum));
            payWxOrderItem.setItemActivityId(null);
            payWxOrderItem.setItemActivityFee(null);
            payWxOrderItem.setItemWaitPayFee(payWxOrderItem.getItemTotalFee());
            payWxOrderItem.setCreateTime(new Date());
            payWxOrderItem.setUpdateTime(new Date());
            payWxOrderItemMapper.insert(payWxOrderItem);
        }
        //2.3 调用微信预支付接口
        Map map = WxUtil.wxPay(app_id,
                mch_id,
                CommonConstant.DESCRIPTION,
                wpNo,
                payWxOrder.getWaitPayFee().multiply(new BigDecimal(100)).toString(),
                ip,
                call_back_url_domain + call_back_mapping,
                api_key,
                foundationSysUser.getWxId());
        WxPayResponse wxLoginRes = (WxPayResponse) CommonUtil.mapToObject(map, WxPayResponse.class);
        //给前端算签名
        String timeStamp = new Date().getTime() + "";
        log.info("wxLoginRes = {}", wxLoginRes.toString());
        if (CommonConstant.SUCCESS.equalsIgnoreCase(wxLoginRes.getReturn_code())) {
            if (CommonConstant.SUCCESS.equalsIgnoreCase(wxLoginRes.getResult_code())) {
                String sign = WxUtil.frontSign(app_id,
                        timeStamp,
                        wxLoginRes.getNonce_str(),
                        wxLoginRes.getPrepay_id(),
                        api_key);
                wxLoginRes.setSign(sign);
                wxLoginRes.setTimestamp(timeStamp);
                log.info("返回给前端的参数 = {}", wxLoginRes.toString());
                baseResult = new BaseResult(wxLoginRes);
            } else {
                baseResult = new BaseResult(ErrorCodeEnum.PAY_EXCEPTION.getCode(), wxLoginRes.getErr_code_des());
            }
        } else {
            baseResult = new BaseResult(ErrorCodeEnum.TCP_EXCEPTION.getCode(), "网络不稳定");
        }
        log.info("[service] [OUT] editPayOrder success ");
        return baseResult;
    }

    @Override
    public void wxPayCallBack(Map<String, Object> map) {
        String out_trade_no = (String)map.get("out_trade_no");
        String transaction_id = (String)map.get("transaction_id");
        String cash_fee1 = (String) map.get("cash_fee");
        Integer cash_fee = Integer.parseInt(cash_fee1);
        //对账支付订单
        PayWxOrder payWxOrder = payWxOrderMapper.getOrderByPayOrderNo(out_trade_no);
        payWxOrder.setWxTransactionId(transaction_id + "");
        payWxOrder.setActualPayFee(DataConvertUtil.intToBigdecimal(cash_fee));
        payWxOrder.setRecordStatus(PayWxOrderStatusEnum.AUDIT.getCode());
        if (payWxOrder.getActualPayFee().compareTo(payWxOrder.getWaitPayFee()) == 0){
            payWxOrder.setMonthAccountCheckingStatus(MonthCheckEnum.CHECK_SUCCESS.getCode());
            //变更业务订单状态为已支付
            PayBusinessOrder payBusinessOrder = payBusinessOrderMapper.getByBusinessNo(payWxOrder.getBusinessOrderNo());
            payBusinessOrder.setRecordStatus(PayBusinessOrderEnum.PAYED.getCode());
            payBusinessOrderMapper.updateByPrimaryKeySelective(payBusinessOrder);
        }else {
            payWxOrder.setMonthAccountCheckingStatus(MonthCheckEnum.CHECK_FAIL.getCode());
        }
        payWxOrder.setCheckBillTime(new Date());
        payWxOrderMapper.updateByPrimaryKeySelective(payWxOrder);
        BigDecimal walletFee = payWxOrder.getWalletFee();
        if (walletFee.compareTo(new BigDecimal(0)) > 0){
            //扣减钱包金额
            FoundationSysUser foundationSysUser = sysUserMapper.selectByPrimaryKey(payWxOrder.getUserId());
            sysUserMapper.updateWalletAmount(foundationSysUser.getId(), walletFee.multiply(new BigDecimal(-1)));
            //生成钱包流水
            PayUserWalletFlow payUserWalletFlow = new PayUserWalletFlow();
            payUserWalletFlow.setRecordStatus(StatusEnum.EFFECTIVE_STATUS.getStatusCode());
            payUserWalletFlow.setWalletType(FlowTypeEnum.OUT.getCode());
            payUserWalletFlow.setBalance(walletFee.multiply(new BigDecimal(-1)));
            payUserWalletFlow.setBusinessOrderNo(payWxOrder.getBusinessOrderNo());
            payUserWalletFlow.setPayOrderNo(payWxOrder.getPayOrderNo());
            payUserWalletFlow.setOuterOrderNo(transaction_id + "");
            payUserWalletFlow.setCreateTime(new Date());
            payUserWalletFlow.setUpdateTime(new Date());
            payUserWalletFlowMapper.insert(payUserWalletFlow);
        }
    }
}
